package pl.dsp.dsp1.ui;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;

import pl.dsp.dsp1.processing.ComplexValue;
import pl.dsp.dsp1.processing.Signal;
import pl.dsp.dsp1.processing.SignalValue;
import pl.dsp.dsp1.processing.SimpleValue;

public class SignalBytes {
	private static final byte[] PREAMBLE = "APKD_SIG".getBytes();

	private Signal signal;

	public Signal getSignal() {
		return signal;
	}

	private byte[] bytes;

	public byte[] getBytes() {
		return bytes;
	}

	public SignalBytes(byte[] bytes) {
		this.bytes = new byte[bytes.length];
		System.arraycopy(bytes, 0, this.bytes, 0, bytes.length);

		try {
			signal = parseBytes();
		} catch (IOException e) {
			e.printStackTrace();
			signal = null;
		}
	}

	private Signal parseBytes() throws IOException {
		ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);

		byte[] preamble = new byte[PREAMBLE.length];
		byteBuffer.get(preamble, 0, PREAMBLE.length);
		if (!new String(preamble).equals(new String(PREAMBLE)))
			throw new IOException();

		double samplingPeriod = byteBuffer.getDouble();
		double t1 = byteBuffer.getDouble();
		int dimensions = byteBuffer.getInt();
		int length = byteBuffer.getInt();

		Signal signal = new Signal(t1, samplingPeriod);

		parseBody(byteBuffer, signal, dimensions, length);

		return signal;
	}

	private void parseBody(ByteBuffer byteBuffer, Signal signal,
			int dimensions, int length) {
		for (int index = 0; index < length; index++) {
			if (dimensions == 1) {
				signal.add(new SimpleValue(byteBuffer.getDouble()));
			} else if (dimensions == 2) {
				signal.add(new ComplexValue(byteBuffer.getDouble(), byteBuffer
						.getDouble()));
			}
		}
	}

	public SignalBytes(Signal signal) {
		this.signal = new Signal(signal);
		try {
			bytes = parseSignal();
		} catch (IOException e) {
			e.printStackTrace();
			bytes = null;
		}
	}

	private byte[] parseSignal() throws IOException {
		ByteArrayOutputStream byteStream = new ByteArrayOutputStream();

		writeHeader(byteStream);
		writeBody(byteStream);

		return byteStream.toByteArray();
	}

	private void writeBody(ByteArrayOutputStream byteStream) throws IOException {
		for (SignalValue value : signal) {
			for (int dimension = 0; dimension < signal.getDimensions(); dimension++) {
				byteStream.write(ByteBuffer.allocate(8)
						.putDouble(value.getValues().get(dimension)).array());
			}
		}
	}

	private void writeHeader(ByteArrayOutputStream byteStream)
			throws IOException {
		byteStream.write(PREAMBLE);
		byteStream.write(ByteBuffer.allocate(8)
				.putDouble(signal.getSamplingPeriod()).array());
		byteStream.write(ByteBuffer.allocate(8).putDouble(signal.getT1())
				.array());
		byteStream.write(ByteBuffer.allocate(4).putInt(signal.getDimensions())
				.array());
		byteStream.write(ByteBuffer.allocate(4)
				.putInt(signal.getXAxis().size()).array());
	}

}
